﻿using AutoMapper;
using crip.Common;
using crip.Dtos;
using crip.Helper;
using crip.Models;
using crip.ResourceParameters;
using crip.Services.IRepositorys;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
using Microsoft.AspNetCore.Identity;

namespace crip.Controllers
{
    /// <summary>
    /// 事件
    /// </summary>
    [Route("api/event")]
    [ApiController]
    public class EventController : ControllerBase
    {
        #region 依赖注入
        //用户工具包
        private readonly UserManager<CripUser> _userManager;
        private readonly IMapper _mapper;
        private IEventRepository _eventRepository;
        //链接生成工具
        private readonly IUrlHelper _urlHelper;
        //使用HttpContext的接口
        private readonly IHttpContextAccessor _httpContextAccessor;
        public EventController(
            IMapper mapper,
            UserManager<CripUser> userManager,
            IEventRepository eventRepository,
            IUrlHelperFactory urlHelperFactory,
            IHttpContextAccessor httpContextAccessor,
            IActionContextAccessor actionContextAccessor//定义用于公开操作上下文的接口。
        )
        {
            _mapper = mapper;
            _eventRepository = eventRepository;
            _userManager = userManager;
            _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);//作为 HTTP 请求的一部分选择的执行操作的上下文对象
            _httpContextAccessor = httpContextAccessor;
        }
        #endregion

        #region URL私有方法

        #region 生成GetURL
        private string GenerateCripResourceURL(
          EventParameter eventParameter,
          PaginationResourceParamaters paginationResourceParamaters,
          ResourceURLType type
          )
        {
            return type switch
            {
                ResourceURLType.PreviousPage => _urlHelper.Link("GetEvents",
                new
                {
                    keyword = eventParameter.Keyword,
                    orderby = eventParameter.OrderBy,
                    pageNumber = paginationResourceParamaters.PageNumber - 1,
                    pageSize = paginationResourceParamaters.PageSize
                }),
                ResourceURLType.NextPage => _urlHelper.Link("GetEvents",
                new
                {
                    keyword = eventParameter.Keyword,
                    orderby = eventParameter.OrderBy,
                    pageNumber = paginationResourceParamaters.PageNumber + 1,
                    pageSize = paginationResourceParamaters.PageSize
                }),
                _ => _urlHelper.Link("GetEvents",
                new
                {
                    keyword = eventParameter.Keyword,
                    orderby = eventParameter.OrderBy,
                    pageNumber = paginationResourceParamaters.PageNumber,
                    pageSize = paginationResourceParamaters.PageSize
                }
                )
            };
        }
        #endregion

        #region hateoas自我发现Event链接

        #region 多个资源CreateLinksForEventList
        private IEnumerable<LinkDto> CreateLinksForEventList(
          EventParameter eventParameter,
          PaginationResourceParamaters paginationResourceParamaters)
        {
            var links = new List<LinkDto>();
            // 添加self，自我链接
            links.Add(new LinkDto(
                   GenerateCripResourceURL(
                        eventParameter, paginationResourceParamaters, ResourceURLType.CurrnetPage),
                    "self",
                    "GET"
                ));

            // "api/events"
            // 添加创建旅游路线
            links.Add(new LinkDto(
                    Url.Link("CreateEvent", null),
                    "create_event",
                    "POST"
                ));

            return links;
        }
        #endregion

        #region 单一资源CreateLinkForEvent
        private IEnumerable<LinkDto> CreateLinkForEvent(Guid eventId)
        {
            var links = new List<LinkDto>();

            links.Add(
                new LinkDto(
                    Url.Link("GetEventById", new { eventId }),
                    "self",
                    "GET"
                    )
                );

            return links;
        }
        #endregion


        #endregion

        #endregion

        #region 发布事件
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <param name="eventDto"></param>
        /// <returns></returns>
        #region 设置允许请求的媒体类型
        [Produces(
            "application/json",
            "application/vnd.crip.hateoas+json",
            "application/vnd.crip.Area.simplify+json",
            "application/vnd.crip.Area.simplify.hateoas+json"
            )]
        #endregion


        [HttpPost]
        [Authorize(AuthenticationSchemes = "Bearer")]
        public async Task<IActionResult> PubulishEvent([FromBody] EventForCreationDto eventDto)
        {
            PagesResponse pagesResponse = new PagesResponse();
            var userId = _httpContextAccessor
           .HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;//获取jwt中的UserId
            var user = await _userManager.FindByIdAsync(userId);
            if (user == null)
            {
                pagesResponse.NotFound("用户不存在");
                return NotFound(pagesResponse);
            }
            eventDto.CreateUserId = userId;
            var eventRepo = _mapper.Map<Event>(eventDto);
            var res = await _eventRepository.AddEventAsync(eventRepo);
            await _eventRepository.SaveAsync();
            if (res == false )
            {
                pagesResponse.BadRequest("事件创建失败");
                return BadRequest(pagesResponse);
            }
            pagesResponse.Success("事件创建成功");
            return Ok(pagesResponse);
        }
        #endregion

        #region 模糊查找
        /// <summary>
        /// 模糊查找
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> GetEventsAsync(
            [FromQuery] EventParameter eventParameter,
            [FromQuery] PaginationResourceParamaters paginationResourceParamaters,
            [FromHeader(Name = "Accept")] string mediaType
            )
        {
            PagesResponse pagesResponse = new PagesResponse();

            #region 获取资源与校验
            //获取媒体类型
            if (!MediaTypeHeaderValue.TryParse(mediaType, out MediaTypeHeaderValue parsedMediatype))
            {
                pagesResponse.BadRequest("未查找到媒体类型");
            }

            //从仓库获得分页资源
            var eventRepo = await _eventRepository
            .GetEventsAsync(
                eventParameter.Keyword,
                eventParameter.OrderBy,
                eventParameter.Desc,
                paginationResourceParamaters.PageNumber,
                paginationResourceParamaters.PageSize
                );

            if (eventRepo == null || eventRepo.Count() == 0)
            {
                pagesResponse.NotFound("事件不存在");
                return NotFound(pagesResponse);
            }
            #endregion

            #region 分页URL
            //上一页的url
            var previousPageLink = eventRepo.HasPrevious
          ? GenerateCripResourceURL(
             eventParameter, paginationResourceParamaters, ResourceURLType.PreviousPage)
          : null;
            //下一页的url
            var nextPageLink = eventRepo.HasNext
          ? GenerateCripResourceURL(
             eventParameter, paginationResourceParamaters, ResourceURLType.NextPage)
          : null;
            #endregion

            #region 设置URL

            // x-pagination水平分页
            var paginationMetadata = new
            {
                previousPageLink,
                nextPageLink,
                totalCount = eventRepo.TotalCount,
                pageSize = eventRepo.PageSize,
                currentPage = eventRepo.CurrentPage,
                totalPages = eventRepo.TotalPages
            };
            HttpResponseHelper httpResponseHelper = new HttpResponseHelper();


            //分页链接设置到响应头
            httpResponseHelper.SetHeader("x-pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetadata), Response);//信息设置到header
            #endregion

            #region 媒体资源类型获取
            //截取是否hateoas请求
            bool isHateoas = parsedMediatype.SubTypeWithoutSuffix
                .EndsWith("hateoas", StringComparison.InvariantCultureIgnoreCase);
            //截取主要请求的媒体类型
            var primaryMediaType = isHateoas
                ? parsedMediatype.SubTypeWithoutSuffix
                    .Substring(0, parsedMediatype.SubTypeWithoutSuffix.Length - 8)
                : parsedMediatype.SubTypeWithoutSuffix;
            IEnumerable<object> eventsDto;
            #endregion

            #region 分类封装
            //当请求的媒体类型为简化资源
            if (primaryMediaType == "vnd.crip.Event.simplify")
            {
                eventsDto = _mapper.Map<IEnumerable<EventSimplifyDto>>(eventRepo);
            }
            else//非简化资源时
            {
                eventsDto = _mapper.Map<IEnumerable<EventDto>>(eventRepo);
            }

            if (isHateoas)//请求Hateoas媒体资源
            {
                var links = CreateLinksForEventList(eventParameter, paginationResourceParamaters);
                var hateoasRes = new
                {
                    Events = eventsDto,
                    links = links
                };
                pagesResponse.Success(hateoasRes, "已查询");
                return Ok(pagesResponse);
            }
            else
            {
                var res = new
                {
                    Events = eventsDto
                };
                pagesResponse.Success(res, "已查询");
                return Ok(pagesResponse);
            }

            #endregion

        }
        #endregion

        #region GetEventByIdAsync
        [HttpGet("{eventId:Guid}", Name = "GetEventById")]
        public async Task<IActionResult> GetEventByIdAsync(
           [FromRoute] Guid eventId
           )
        {
            PagesResponse pagesResponse = new PagesResponse();
            var myevent = await _eventRepository.GetEventByEventIdAsync(eventId);
            if (myevent == null)
            {
                pagesResponse.NotFound("事件不存在");
                return Ok(pagesResponse);
            }
            var eventRes = _mapper.Map<EventDto>(myevent);
            var res = new
            {
                Event = eventRes
            };
            pagesResponse.Success(res, "查询成功");
            return Ok(pagesResponse);
        }
        #endregion

        #region 删除事件

        /// <summary>
        /// 删除事件
        /// </summary>
        /// <param name="eventId"></param>
        /// <returns></returns>
        [HttpDelete("{eventId:Guid}")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        public async Task<IActionResult> DeleteEventByIdAsync([FromRoute] Guid eventId)
        {
            PagesResponse pagesResponse = new PagesResponse();
            var mevent = await _eventRepository.GetEventByEventIdAsync(eventId);
            var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
            if (mevent.CreateUserId != userId)
            {
                pagesResponse.BadRequest("您没有该权限删除此区域");
                return BadRequest(pagesResponse);
            }
            else
            {
                _eventRepository.Delete(mevent);
                await _eventRepository.SaveAsync();
                pagesResponse.Success("已删除");
                return Ok(pagesResponse);
            }
        }
        #endregion
    }
}
